#include <string.h>
#include "gd32l23x_fmc.h"
#include "iap_handle.h"
#include "rs485_app.h"


typedef void (*jump_callback) (void);
typedef  void (*pFunction)(void);

volatile uint32_t vg_uiIapWaitTimeMs = 6000;
volatile uint8_t vg_ucWaitTimeOutFlag = 0;
volatile uint8_t vg_ucLastSerialNo = 0;
volatile uint8_t vg_ucIapEraseOverFlag = 0;
volatile uint8_t vg_ucIapLoadOverFlag = 0;
volatile uint32_t vg_uiBackAddr = 0;

uint32_t JumpAddress;
pFunction JumpToApplication;

BIN_FILE_INFO_T g_stBinFlieInfo = {0};
uint8_t ucaReadFlashBuf[IF_FLASH_PAGE_SIZE] = {0};


/***************************************************************************************************
 * 函 数 名  : UartHandle_Ack_Cmd
 * 创建日期  : 2024年12月14日
 * 函数功能  : 串口应答指令执行状态
 * 输入参数  : IN uint8_t ucCmd     应答的命令码
               IN uint8_t ucStatus  指令执行状态值
 * 输出参数  : 无
 * 返 回 值  : 
 * 调用关系  : main、UartHandle_Cmd_Execute ---> UartHandle_Ack_Cmd
               crc16_modbus、Uart_Send_Buf <--- UartHandle_Ack_Cmd
*****************************************************************************************************/
void UartHandle_Ack_Cmd(IN uint8_t ucCmd, IN uint8_t ucStatus)
{
	uint16_t crc16 = 0;
    uint8_t g_ucSendBuf[SEND_DATA_BUF_SIZE] = {0};

	g_ucSendBuf[0] = UART_DATA_HEAD_H;
	g_ucSendBuf[1] = UART_DATA_HEAD_L;
	g_ucSendBuf[2] = 0;
	g_ucSendBuf[3] = 0x07;
	g_ucSendBuf[4] = 0xB0;
	g_ucSendBuf[5] = ucCmd;
	g_ucSendBuf[6] = ucStatus;

	crc16 = CRC16_MODBUS((unsigned char*)g_ucSendBuf, 7);
	g_ucSendBuf[7] = (uint8_t)(crc16 & 0xff);
	g_ucSendBuf[8] = (uint8_t)((crc16&0xff00)>>8);

    usart0_tx(g_ucSendBuf, 9); //发送数据
}

/***************************************************************************************************
 * 函 数 名  : UartHandle_Cmd_Execute
 * 创建日期  : 2024年12月14日
 * 函数功能  : 串口指令处理执行
 * 输入参数  : IN UART_FRAM_T *pstFramCfg  指令数据指针
 * 输出参数  : 无
 * 返 回 值  : 
 * 调用关系  : UartHandle_RecAndOperate ---> UartHandle_Cmd_Execute
               UartHandle_Ack_Cmd、Iap_If_Erase、Iap_Data_Crc16Check <--- UartHandle_Cmd_Execute
               Iap_Data_Write、Iap_Data_ReadAndCmp、Iap_Set_LoadOverFlag <--- UartHandle_Cmd_Execute
*****************************************************************************************************/
void UartHandle_Cmd_Execute(IN UART_FRAM_T *pstFramCfg)
{
	uint8_t ucResult = DEV_SUCCESS;
	uint32_t uiDataLen = 0;
	uint8_t ucaBuf[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

	if (NULL == pstFramCfg)
	{
		return;
	}

	/* 升级命令 */
	if (CMD_UPDATE_E != pstFramCfg->ucCmd)
	{
		UartHandle_Ack_Cmd(pstFramCfg->ucCmd, CMD_NOTSUPORT);
		return;
	}

	/* 有效数据长度 */
	uiDataLen = ((pstFramCfg->usFramLenH << 8) | pstFramCfg->usFramLenL) - 6;
	if ((0 == uiDataLen) || (uiDataLen > DATA_MAX))
	{
		UartHandle_Ack_Cmd(pstFramCfg->ucCmd, DATA_LEN_ERROR);
		return;
	}

	/* 帧序号连续 */
	if (0 != pstFramCfg->ucFramSerialNo) 
	{
		if (vg_ucLastSerialNo == pstFramCfg->ucFramSerialNo)
		{
			UartHandle_Ack_Cmd(pstFramCfg->ucCmd, DEV_SUCCESS);
			return;
		}

		if ((vg_ucLastSerialNo + 1) != pstFramCfg->ucFramSerialNo)
		{
			UartHandle_Ack_Cmd(pstFramCfg->ucCmd, PACK_LOSS);
			return;
		}

		/* 升级程序 */
		vg_ucLastSerialNo = pstFramCfg->ucFramSerialNo;
		vg_uiIapWaitTimeMs = 15000;

		if (0 != vg_ucIapEraseOverFlag)
		{
			
			ucResult = Iap_Data_Write(pstFramCfg->ucaBuf, vg_uiBackAddr, uiDataLen);
			if ((DEV_SUCCESS == ucResult) && \
				(DEV_SUCCESS == Iap_Data_ReadAndCmp(pstFramCfg->ucaBuf, vg_uiBackAddr, MIN(uiDataLen, 8))))
			{
				vg_uiBackAddr += uiDataLen;
				if (vg_uiBackAddr >= (USER_UPDATE_ADDR + g_stBinFlieInfo.uiFileSize))
				{
					vg_uiIapWaitTimeMs = 15000;
					/* 接收完成，进行CRC校验 */
					if (DEV_SUCCESS != Iap_Data_Crc16Check(USER_UPDATE_ADDR, g_stBinFlieInfo.uiFileSize, g_stBinFlieInfo.usFileCrc))
					{
						UartHandle_Ack_Cmd(pstFramCfg->ucCmd, CRC_ERROR);
					}
					else
					{
						if (DEV_SUCCESS == Iap_Set_LoadOverFlag(IAP_UPDATE_FLAG))
						{
							UartHandle_Ack_Cmd(pstFramCfg->ucCmd, DEV_SUCCESS);
							vg_uiIapWaitTimeMs = 1000;
							vg_ucIapLoadOverFlag = 1;
						}
					}
				}
				else
				{
					UartHandle_Ack_Cmd(pstFramCfg->ucCmd, DEV_SUCCESS);
				}
			}
			else
			{
				vg_ucIapEraseOverFlag = 0;
				UartHandle_Ack_Cmd(pstFramCfg->ucCmd, CRC_ERROR);
			}
		}
		else
		{
			vg_ucIapEraseOverFlag = 0;
			UartHandle_Ack_Cmd(pstFramCfg->ucCmd, PACK_LOSS);
		}
	}
	else
	{
		/* 信息帧处理 */
		memset(&g_stBinFlieInfo, 0, sizeof(g_stBinFlieInfo));
		g_stBinFlieInfo.ucBoadNo		= pstFramCfg->ucaBuf[0];
		g_stBinFlieInfo.ucVersionX	= pstFramCfg->ucaBuf[1];
		g_stBinFlieInfo.ucVersionY	= pstFramCfg->ucaBuf[2];
		g_stBinFlieInfo.ucVersionZ	= pstFramCfg->ucaBuf[3];
		g_stBinFlieInfo.ucFramTotal	= pstFramCfg->ucaBuf[4];
		g_stBinFlieInfo.uiFileSize	= ((pstFramCfg->ucaBuf[5] << 16) | (pstFramCfg->ucaBuf[6] << 8)  | pstFramCfg->ucaBuf[7]);
		g_stBinFlieInfo.usFileCrc 	= ((pstFramCfg->ucaBuf[9] << 8) | pstFramCfg->ucaBuf[8]);
		if (g_stBinFlieInfo.uiFileSize > APP_FLASH_SIZE)
		{
			UartHandle_Ack_Cmd(pstFramCfg->ucCmd, NOT_ENOUGH_MEMORY);
			return;
		}

		vg_uiIapWaitTimeMs = 15000;
		/* 擦除 */
		if (DEV_SUCCESS != Iap_If_Erase(USER_UPDATE_ADDR, g_stBinFlieInfo.uiFileSize))
		{
			UartHandle_Ack_Cmd(pstFramCfg->ucCmd, DEV_BUSY);
			return;
		}
		//擦除后再确认是否擦除成功？
		if ((DEV_SUCCESS != Iap_Data_ReadAndCmp(ucaBuf, USER_UPDATE_ADDR, 8)) || \
			(DEV_SUCCESS != Iap_Data_ReadAndCmp(ucaBuf, (USER_UPDATE_ADDR + g_stBinFlieInfo.uiFileSize -1), 1)))
		{
			UartHandle_Ack_Cmd(pstFramCfg->ucCmd, DEV_BUSY);
			return;
		}

		/* 擦除用户数据区 */
		if (DEV_SUCCESS != Iap_If_Erase(USER_DATA_ADDR, sizeof(BIN_FILE_INFO_T)))
		{
			UartHandle_Ack_Cmd(pstFramCfg->ucCmd, DEV_BUSY);
			return;
		}

		//写入数据区
		if ((DEV_SUCCESS == Iap_Data_Write((uint8_t *)&g_stBinFlieInfo, USER_DATA_ADDR, sizeof(BIN_FILE_INFO_T))) && \
			(DEV_SUCCESS == Iap_Data_ReadAndCmp((uint8_t *)&g_stBinFlieInfo, USER_DATA_ADDR, sizeof(BIN_FILE_INFO_T))))
		{
			vg_ucIapEraseOverFlag = 1;
			vg_uiBackAddr = USER_UPDATE_ADDR;
			UartHandle_Ack_Cmd(pstFramCfg->ucCmd, DEV_SUCCESS);
		}
	}
}

/***************************************************************************************************
 * 函 数 名  : Iap_Jump_App
 * 创建日期  : 2024年12月14日
 * 函数功能  : 程序跳转执行
 * 输入参数  : IN uint32_t uiAppAddr  用户程序起始地址
 * 输出参数  : 无
 * 返 回 值  : 无
 * 调用关系  : Iap_Jump_App <--- main
*****************************************************************************************************/
void Iap_Jump_App(IN uint32_t uiAppAddr)
{
	/* Test if user code is programmed starting from address "APPLICATION_ADDRESS" */
    if (((*(__IO uint32_t*)uiAppAddr) & 0x2FFE0000 ) == 0x20000000)
	{
		printf("jump to app>>>>>>>>>>>>>>>>>\r\n");
		delay_1ms(10);
		 /* disable all interrupts */
		 __disable_irq();
		/* Jump to user application */
		JumpAddress = *(__IO uint32_t*) (uiAppAddr + 4);
		JumpToApplication = (pFunction) JumpAddress;
		/* Initialize user application's Stack Pointer */
		__set_MSP(*(__IO uint32_t*) uiAppAddr);
		JumpToApplication();
	}
}


/***************************************************************************************************
 * 函 数 名  : Iap_Data_Crc16Check
 * 创建日期  : 2024年12月14日
 * 函数功能  : 读取内存数据进行Crc校验
 * 输入参数  : IN uint32_t uiAddr       要校验的数据起始地址
               IN uint32_t uiLen        要校验的内存数据长度
               IN uint16_t usCrcModbus  正确的Crc值
 * 输出参数  : 无
 * 返 回 值  : DEV_SUCCESS-校验成功，DEV_ERROR-校验失败
 * 调用关系  : Iap_Data_Crc16Check <--- Iap_Update_BinFile、UartHandle_Cmd_Execute
*****************************************************************************************************/
STATUS_E Iap_Data_Crc16Check(IN uint32_t uiAddr, IN uint32_t uiLen, IN uint16_t usCrcModbus)
{
	uint32_t i;
	uint32_t pos;
	uint16_t Crc_16;

	uint8_t ucTemp = 0;

	/* check if the address is in protected area */
	if ((uiAddr < USER_APP_ADDR) || ((uiAddr + uiLen) > ADDR_MAX_SIZE))
	{
		return DEV_ERROR;
	}

	Crc_16 = 0xFFFF; // 初始值
	for (pos = 0; pos < uiLen; pos++)
	{
		ucTemp = *(uint8_t*)(uiAddr+pos);
		Crc_16 ^= ucTemp;
		for (i = 8; i != 0; i--)
		{ // 处理每一位
			if ((Crc_16 & 0x0001) != 0)
			{
				Crc_16 >>= 1;
				Crc_16 ^= 0xA001;
			}
			else
			{
				Crc_16 >>= 1;
			}
		}
	}

	if (Crc_16 != usCrcModbus)
	{
		return DEV_ERROR;
	}
	
	return DEV_SUCCESS;
}

/***************************************************************************************************
 * 函 数 名  : Iap_Data_ReadAndCmp
 * 创建日期  : 2024年12月14日
 * 函数功能  : 读取内存数据进行校验
 * 输入参数  : IN uint8_t *pucBuf  正确的内存值数组指针
               IN uint32_t uiAddr  要校验的内存数据起始地址
               IN uint32_t uiLen   要校验的数据总长度
 * 输出参数  : 无
 * 返 回 值  : DEV_SUCCESS-校验成功，DEV_ERROR-校验失败
 * 调用关系  : Iap_Data_ReadAndCmp <--- Iap_Set_LoadOverFlag、UartHandle_Cmd_Execute
*****************************************************************************************************/
STATUS_E Iap_Data_ReadAndCmp(IN uint8_t *pucBuf, IN uint32_t uiAddr, IN uint32_t uiLen)
{
	uint32_t i = 0U;
	uint8_t ucTemp = 0;

	/* check if the address is in protected area */
	if ((uiAddr < USER_APP_ADDR) || ((uiAddr + uiLen) > ADDR_MAX_SIZE))
	{
		return DEV_ERROR;
	}

	for (i = 0; i < uiLen; i++)
	{
		ucTemp = *(uint8_t*)(uiAddr+i);
		if (pucBuf[i] != ucTemp)
		{
			return DEV_ERROR;
		}
	}

	return DEV_SUCCESS;
}

/***************************************************************************************************
 * 函 数 名  : Iap_Set_LoadOverFlag
 * 创建日期  : 2024年12月14日
 * 函数功能  : 设置下载完成标志
 * 输入参数  : IN int32_t uiLoadover  要设置的标志值
 * 输出参数  : 无
 * 返 回 值  : DEV_SUCCESS-校验成功，DEV_ERROR-校验失败
 * 调用关系  : UartHandle_Cmd_Execute、Iap_Update_BinFile ---> Iap_Set_LoadOverFlag
               Iap_Set_LoadOverFlag <--- Iap_Data_Read、Iap_If_Erase、Iap_Data_Write、Iap_Data_ReadAndCmp
*****************************************************************************************************/
STATUS_E Iap_Set_LoadOverFlag(IN int32_t uiLoadover)
{
	Iap_Data_Read((uint8_t *)&g_stBinFlieInfo, USER_DATA_ADDR, sizeof(BIN_FILE_INFO_T));
	g_stBinFlieInfo.uiLoadover = uiLoadover;	

	if (DEV_SUCCESS != Iap_If_Erase(USER_DATA_ADDR, sizeof(BIN_FILE_INFO_T)))
	{
		return DEV_BUSY;
	}

	if ((DEV_SUCCESS == Iap_Data_Write((uint8_t *)&g_stBinFlieInfo, USER_DATA_ADDR, sizeof(BIN_FILE_INFO_T))) && \
		(DEV_SUCCESS == Iap_Data_ReadAndCmp((uint8_t *)&g_stBinFlieInfo, USER_DATA_ADDR, sizeof(BIN_FILE_INFO_T))))
	{
		return DEV_SUCCESS;
	}
		
	return DEV_BUSY;
}


/***************************************************************************************************
 * 函 数 名  : Iap_Update_BinFile
 * 创建日期  : 2024年12月14日
 * 函数功能  : 更新用户程序
 * 输入参数  : void
 * 输出参数  : 无
 * 返 回 值  : DEV_SUCCESS-校验成功，DEV_ERROR-校验失败
 * 调用关系  : main ---> Iap_Update_BinFile
               Iap_Update_BinFile <--- Iap_Data_Read、Iap_If_Erase、Iap_Data_Write、Iap_Data_Crc16Check、Iap_Set_LoadOverFlag
*****************************************************************************************************/
STATUS_E Iap_Update_BinFile(void)
{
	STATUS_E eResult = DEV_ERROR;
	uint16_t i, usPageNum = 0;	
//	uint32_t index = 0U;
	uint32_t uiAddr = 0;
	BIN_FILE_INFO_T stBinFileInfo = {0};
	
	Iap_Data_Read((uint8_t *)&stBinFileInfo, USER_DATA_ADDR, sizeof(BIN_FILE_INFO_T));
	if (0 != (stBinFileInfo.uiFileSize % IF_FLASH_PAGE_SIZE))
	{
		usPageNum = (stBinFileInfo.uiFileSize  / IF_FLASH_PAGE_SIZE) + 1;
	}
	else
	{
		usPageNum = (stBinFileInfo.uiFileSize  / IF_FLASH_PAGE_SIZE);
	}

	if (IAP_UPDATE_FLAG != stBinFileInfo.uiLoadover)
	{
		return DEV_SUCCESS;
	}

	eResult = Iap_If_Erase(USER_APP_ADDR, stBinFileInfo.uiFileSize);
	if (DEV_SUCCESS == eResult)
	{
		for (i = 0; i < usPageNum; i++)
		{
			/* 从升级区读取数据 */
			uiAddr = USER_UPDATE_ADDR + i* IF_FLASH_PAGE_SIZE;
			Iap_Data_Read(ucaReadFlashBuf, uiAddr, IF_FLASH_PAGE_SIZE);
			/* 数据写入执行区 */
			uiAddr = USER_APP_ADDR + i* IF_FLASH_PAGE_SIZE;
			eResult = Iap_Data_Write(ucaReadFlashBuf, uiAddr, IF_FLASH_PAGE_SIZE);
			if (DEV_SUCCESS != eResult)
			{
				break;
			}
		}

		if (DEV_SUCCESS == eResult)
		{
			eResult = Iap_Data_Crc16Check(USER_APP_ADDR, stBinFileInfo.uiFileSize, stBinFileInfo.usFileCrc);
			if (DEV_SUCCESS == eResult)
			{
				eResult = Iap_Set_LoadOverFlag(IAP_UPDATE_CLEAR);
			}
		}
	}


	return eResult;
}

/***************************************************************************************************
 * 函 数 名  : Iap_Data_Read
 * 创建日期  : 2024年12月14日
 * 函数功能  : 读取内存数据
 * 输入参数  : IN uint32_t uiAddr   读取内存数据的起始地址
               IN uint32_t uiLen    需要读取的内存数据长度
 * 输出参数  : OUT uint8_t *pucBuf  读取的内存数据缓存指针
 * 返 回 值  : 无
 * 调用关系  : Iap_Update_BinFile <--- Iap_Set_LoadOverFlag、Iap_Update_BinFile
*****************************************************************************************************/
void Iap_Data_Read(OUT uint8_t *pucBuf, IN uint32_t uiAddr, IN uint32_t uiLen)
{
	uint32_t index = 0U;

	/* check if the address is in protected area */
	if ((uiAddr < USER_APP_ADDR) || (uiAddr > ADDR_MAX_SIZE))
	{
		return ;
	}

	/* data received are word multiple */

	for (index = 0U; index < uiLen; index++) 
	{
		pucBuf[index] = *(uint8_t*)(uiAddr+index);
	}
}

/***************************************************************************************************
 * 函 数 名  : Iap_Data_Write
 * 创建日期  : 2024年12月14日
 * 函数功能  : 写入数据到内存
 * 输入参数  : IN uint8_t *pucBuf  要写入的目标数据
               IN uint32_t uiAddr  要写入数据的内存起始地址
               IN uint32_t uiLen  要写入内存的数据长度
 * 输出参数  : 无
 * 返 回 值  : DEV_SUCCESS-校验成功，DEV_ERROR-校验失败
 * 调用关系  : Iap_Set_LoadOverFlag、Iap_Update_BinFile、UartHandle_Cmd_Execute ---> Iap_Update_BinFile
               Iap_Update_BinFile <--- fmc_unlock、__disable_irq、fmc_word_program、fmc_lock
*****************************************************************************************************/
STATUS_E Iap_Data_Write(IN uint8_t *pucBuf, IN uint32_t uiAddr, IN uint32_t uiLen)
{
	uint32_t index = 0U;

	/* check if the address is in protected area */
	if ((uiAddr < USER_APP_ADDR) || (uiAddr > ADDR_MAX_SIZE))
	{
		return DEV_ERROR;
	}

	if (uiLen & 0x03) 
	{
		/* not an aligned data */
		for (index = uiLen; index < ((uiLen & 0xFFFCU) + 4U); index++) 
		{
			pucBuf[index] = 0xFF;
		}
	}

	/* data received are word multiple */
	fmc_unlock();
	__disable_irq();
	for (index = 0U; index < uiLen; index += 4U) 
	{
		fmc_word_program(uiAddr, *(uint32_t *)(pucBuf + index));
		uiAddr += 4U;
	}
	__enable_irq();
	fmc_lock();

	return DEV_SUCCESS;

}

/***************************************************************************************************
 * 函 数 名  : Iap_If_Erase
 * 创建日期  : 2024年12月14日
 * 函数功能  : 内存扇区擦除
 * 输入参数  : IN uint32_t uiAddr     要擦除的内存起始地址
               IN uint32_t uiFileLen  要擦除的内存长度
 * 输出参数  : 无
 * 返 回 值  : DEV_SUCCESS-校验成功，DEV_ERROR-校验失败
 * 调用关系  : Iap_Set_LoadOverFlag、Iap_Update_BinFile、UartHandle_Cmd_Execute ---> Iap_Update_BinFile
               Iap_Update_BinFile <--- fmc_unlock、__disable_irq、fmc_word_program、fmc_lock
*****************************************************************************************************/
STATUS_E Iap_If_Erase(IN uint32_t uiAddr, IN uint32_t uiFileLen)
{
	uint16_t i, usPageNum = 0;	
	uint32_t uiTemmAddr = 0U;

	if (0 != (uiAddr % IF_FLASH_PAGE_SIZE))
	{
		return DEV_ERROR;
	}

	if (0 != (uiFileLen % IF_FLASH_PAGE_SIZE))
	{
		usPageNum = (uiFileLen / IF_FLASH_PAGE_SIZE) + 1;
	}
	else
	{
		usPageNum = (uiFileLen / IF_FLASH_PAGE_SIZE);
	}

	/* check if the address is in protected area */
	if ((uiAddr < USER_APP_ADDR) || (uiAddr > ADDR_MAX_SIZE)) 
	{
		return DEV_ERROR;
	}


	uiTemmAddr = uiAddr;

	/* unlock the flash program erase controller */
	fmc_unlock();
	__disable_irq();
	for (i=0; i < usPageNum; i++) 
	{
		/* call the standard flash erase-page function */
		fmc_page_erase(uiTemmAddr);

		uiTemmAddr += IF_FLASH_PAGE_SIZE;
	}
	__enable_irq();
	fmc_lock();

	return DEV_SUCCESS;
}

void Init_Board_Info(BIN_FILE_INFO_T info)
{
	BIN_FILE_INFO_T stBinFileInfo = {0};
    uint8_t hdwVersion = 0;
	
	Iap_Data_Read((uint8_t *)&stBinFileInfo, USER_DATA_ADDR, sizeof(BIN_FILE_INFO_T));
    Iap_Data_Read((uint8_t *)&hdwVersion, HDWARE_VERSION_ADDR, sizeof(uint8_t));
    stBinFileInfo.ucVersionX = info.ucVersionX;
    stBinFileInfo.ucVersionY = info.ucVersionY; 
    stBinFileInfo.ucVersionZ = info.ucVersionZ;

    Iap_If_Erase(USER_DATA_ADDR, sizeof(BIN_FILE_INFO_T));
    Iap_Data_Write((uint8_t *)&stBinFileInfo, USER_DATA_ADDR, sizeof(BIN_FILE_INFO_T));
    Iap_Data_Write((uint8_t *)&hdwVersion, HDWARE_VERSION_ADDR, sizeof(uint8_t));
}





